/**
 *******************************************************************************
 * \brief   CAS EBX Project Work "Kaffeemaschine"
 *
 * \file    brew.c
 * \version 1.0
 * \date    30.06.2010
 * \author  Baehler Thomas, Liechti Beat, Sauter Marc
 * \author  Vuksic Valentina, Zbinden Rene
 *
 * \remark  Last Modifications:
 * \remark  V1.0, 30.06.2010   Initial release
 *******************************************************************************
 **/

/*
 *******************************************************************************
 * Definitions
 *******************************************************************************
 */
/** \brief The minimum amount of water needed for a coffee */
#define AMOUNT_OF_WATER 1
/** \brief The minimum water temperature for a coffee */
#define TEMP 1


/*
 *******************************************************************************
 * Imports
 *******************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>

#include "coffee2.h"
#include "channel.h"
#include "pool.h"
#include "device.h"

/*
 *******************************************************************************
 * Local Variables
 *******************************************************************************
 */
static tChannel *c12, *c13; /*, *c27, *c28, *c29, *c30;*/
static tPool *p2, *p3;
static tDevice *d27, *d28, *d29, *d30;
static int timeExpired;


/*
 *******************************************************************************
 * Local Function Declaration
 *******************************************************************************
 */
static void sigtermHandler(int signal);
static void setTimeExpired(int signal);


/**
 *******************************************************************************
 * setTimeExpired
 *
 * \brief handle SIGALRM signal, set timeExpired
 *
 *******************************************************************************
 **/
static void setTimeExpired(int signal) {
	timeExpired = 1;
	return;
}


/**
 *******************************************************************************
 * sigtermHandler
 *
 * \brief handle SIGTERM signal, close all pools and channels and exit
 *
 *******************************************************************************
 **/
static void sigtermHandler(int signal) {
	syslog(LOG_INFO, "SIGTERM reveiced, stopping ...");
	/* open channels and pools */
	closeChannel(c12);
	closeChannel(c13);
	//closeChannel(c27);
	//closeChannel(c28);
	//closeChannel(c29);
	//closeChannel(c30);
	closeDevice(d27);
	closeDevice(d28);
	closeDevice(d29);
	closeDevice(d30);
	closePool(p2);
	closePool(p3);
	/* close syslog */
	closelog();
	/* close and remove the runfile */
	exit(EXIT_SUCCESS);
}


/**
 *******************************************************************************
 * mainBrew
 *
 * \brief Activity: "Wasser"
 *
 * \return pid
 *
 *******************************************************************************
 **/
pid_t mainBrew(){
	pid_t pid;
	sigset_t sigmask;
	struct sigaction sigtermAction;
	enum e_errors error = NO_ERROR;
	int order = 0;
	int parameter = 0;
	int on = 1, off = 0;
	int waterTemp = 0;
	int waterAmount = 0;

	pid = fork();
	if (pid == 0) {
		/* syslog */
		openlog("coffee-brew", LOG_PID, LOG_DAEMON);
		/* block all signals other than SIGTERM */
		sigemptyset(&sigmask);
		sigaddset(&sigmask, SIGTERM);
		sigtermAction.sa_handler = sigtermHandler;
		sigtermAction.sa_mask = sigmask;
		if (sigaction(SIGTERM, &sigtermAction, NULL) == -1){
			syslog(LOG_ERR, "unable to setup signal handling!");
		}
		/* register alarm function */
		if (signal(SIGALRM, setTimeExpired) == SIG_ERR) {
			syslog(LOG_ERR, "can't register SIGALRM!");
		}
		/* open channels and pools */
		c12 = openChannelRead("C12", sizeof(int));  /* read from "Kaffe" */
		c13 = openChannelWrite("C13", sizeof(int)); /* write to "Milk" */
		//c27 = openChannelRead("C27", sizeof(int));  /* read from "Wassertemp"*/
		//c28 = openChannelWrite("C28", sizeof(int)); /* write to
		//												"Durchlauferhitzer */
		//c29 = openChannelRead("C29", sizeof(int)); /* read from "Wassermenge" */
		//c30 = openChannelWrite("C30", sizeof(int)); /* read from "Wasserpump*/
		d27 = openDeviceRead("/dev/c2watrtmp");
		d28 = openDeviceWrite("/dev/c2watrhtr");
		d29 = openDeviceRead("/dev/c2watrmtr");
		d30 = openDeviceWrite("/dev/c2watrpmp");
		p2 = openPool("P2", sizeof(parameter));     /* "Parameter" */
		p3 = openPool("P3", sizeof(error));         /* "Error" */

		while (1) {
			if (readChannel(c12, &order) > 0) {
				syslog(LOG_INFO, "order from C12 received");
				/* read the parameter */
				readFromPool(p2, &parameter);
				/* start the coffee brew */
				syslog(LOG_INFO, "starting water heater");
				//writeChannel(c28, &on);
				writeDevice(d28, on);
				/* wait until correct temperature is reached. */
				alarm(WAIT_FOR_WATER_TEMP_TIMEOUT);
				//readChannel(c27, &waterTemp);
				readDevice(d27, &waterTemp);
				while (waterTemp < TEMP  && timeExpired == 0) {
					usleep(500);
					//readChannel(c27, &waterTemp);
					readDevice(d27, &waterTemp);
				}
				alarm(0);
				if (timeExpired == 1){
					syslog(LOG_ERR, "water temperature not reached");
					error = HEAT_TIMEOUT;
					/* heater seems to be defective ... */
					writeToPool(p3, &error);
					/* heater seems to be defective ... */
				}else{
					/* start water pump */
					syslog(LOG_INFO, "start water pump");
					//writeChannel(c30, &on);
					writeDevice(d30, on);
					syslog(LOG_INFO, "checking amount of water  ...");
					alarm(WAIT_FOR_WATER_TIMEOUT);
					//readChannel(c29, &waterAmount);
					readDevice(d29, &waterAmount);
					while (waterAmount < AMOUNT_OF_WATER && timeExpired == 0) {
						usleep(500);
						//readChannel(c29, &waterAmount);
						readDevice(d29, &waterAmount);
					}
					alarm(0);
					if (timeExpired == 1){
						syslog(LOG_ERR, "water mark not reached");
						error = WATER_TIMEOUT;
						/* water pump seems to be defective ... */
						writeToPool(p3, &error);

					}
					/* stop water heater in any case */
					syslog(LOG_INFO, "stopping water heater");
					//writeChannel(c28, &off);
					writeDevice(d28, off);
					/* start water pump in any case */
					syslog(LOG_INFO, "stop water pump");
					//writeChannel(c30, &off);
					writeDevice(d30, off);
					/* in case of error stop at this point */
					if (timeExpired != 1){
						syslog(LOG_INFO, "sending order to C13");
						writeChannel(c13, &order);
					}
				}
			}
			usleep(500);
		}
	}
	return pid;
}






